#ifndef __COMPILE_RUN_HPP__
#define __COMPILE_RUN_HPP__

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <unistd.h>
#include "compiler.hpp"
#include "runner.hpp"

namespace ns_compile_and_run
{
    using namespace ns_compiler;
    using namespace ns_runner;

    class CompileAndRun
    {
    private:
        static std::string CodeToDesc(int code,const std::string& file_name)
        {
            std::string desc;
            switch(code)
            {
                case 0:
                    desc="编译运行成功";
                    break;
                case -1:
                    desc="提交上来的代码为空";
                    break;
                case -2:
                    desc="未知错误";
                    break;
                case -3:
                    FileUtil::ReadFile(PathUtil::CompileError(file_name),&desc,true);
                    break;
                case SIGABRT:
                    desc="内存超过范围";
                    break;
                case SIGXCPU:
                    desc="CPU使用超时";
                    break;
                case SIGFPE:
                    desc="浮点数错误";
                    break;
                default :
                    desc="未知:"+std::to_string(code);
                    break;
            }
            return desc;
        }

        static void RemoveTempFile(const std::string& file_name)
        {
            std::string _src=PathUtil::Src((file_name));
            if(FileUtil::IsFileExists(_src)==true) unlink(_src.c_str());

            std::string _compile_error=PathUtil::CompileError(file_name);
            if(FileUtil::IsFileExists(_compile_error)==true) unlink(_compile_error.c_str());

            std::string _execute=PathUtil::Exe(file_name);
            if(FileUtil::IsFileExists(_execute)==true) unlink(_execute.c_str());

            std::string _stdin=PathUtil::Stdin(file_name);
            if(FileUtil::IsFileExists(_stdin)==true) unlink(_stdin.c_str());

            std::string _stdout=PathUtil::Stdout(file_name);
            if(FileUtil::IsFileExists(_stdout)==true) unlink(_stdout.c_str());

            std::string _stderr=PathUtil::Stderr(file_name);
            if(FileUtil::IsFileExists(_stderr)==true) unlink(_stderr.c_str());
        }

    public:
        /* ***********************************
        * 输入:
        *   code: 用户提交的代码
        *   input: 用户给自己提交的代码对应的输入，不做处理
        *   cpu_limit: CPU超时时间
        *   mem_limit: 空间大小设置(kb)
        *
        * 输出:
        * 必填
        *   status: 状态码
        *   reason: 请求结果
        * 选填
        *   stdout: 我的程序运行完的结果
        *   stderr: 我的程序运行完的错误结果
        *
        * 状态码:
        *   -1: 提交上来的代码为空
        *   -2: 内部未知错误
        *   -3: 编译过程出现错误
        *   >0: 程序运行过程中崩溃了，返回信号
        *   =0: 程序正常运行完
        * 
        * ************************************/
        static void Start(const std::string& in_json,std::string* out_json)
        {
            /*反序列化*/
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json,in_value);

            /*提取Json::Value中的数据*/
            std::string code=in_value["code"].asString();
            std::string input=in_value["input"].asString();
            int cpu_limit=in_value["cpu_limit"].asInt();
            int mem_limit=in_value["mem_limit"].asInt();

            /*构成响应数据*/
            int status_code=0;
            Json::Value out_value;
            int run_result=0;
            std::string file_name;//需要内部形成唯一文件名

            /*有效数据判断*/
            if(code.size()==0)
            {
                //提交上来的代码为空
                status_code=-1;//
                goto END;
            }

            /*形成具有唯一标识的文件名
            毫秒级时间戳+原子性递增唯一值 来保证文件名的唯一性*/
            file_name=FileUtil::UniqFileName();
            
            /*形成src临时文件*/
            if(FileUtil::WriteFile(PathUtil::Src(file_name),code)==false)
            {
                status_code=-2;//内部未知错误
                goto END;
            }

            /*开始编译*/
            if(Compiler::Compile(file_name)==false)
            {
                status_code=-3;//代码编译过程中发生错误
                goto END;
            }

            /*开始执行可执行文件*/
            run_result=Runner::Run(file_name,cpu_limit,mem_limit);
            if(run_result<0)
            {
                status_code=-2;//内部未知错误
            }
            else if(run_result>0)
            {
                status_code=run_result;//程序运行崩溃了，返回信号
            }
            else
            {
                status_code=0;//程序正常执行完
            }

        END:
            out_value["status"]=status_code;
            out_value["reason"]=CodeToDesc(status_code,file_name);
            /*整个过程全部成功*/
            if(status_code==0)
            {
                /*读取标准输出文件*/
                std::string _stdout;
                FileUtil::ReadFile(PathUtil::Stdout(file_name),&_stdout,true);
                out_value["stdout"]=_stdout;

                /*读取标准错误文件*/
                std::string _stderr;
                FileUtil::ReadFile(PathUtil::Stderr(file_name),&_stderr,true);
                out_value["stderr"]=_stderr;
            }
            Json::StyledWriter writer;
            *out_json=writer.write(out_value);

            /*清理生成的临时文件*/
            RemoveTempFile(file_name);
        }
    };
}

#endif